﻿using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Net;
using System.Reactive;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Catel.Data;
using Catel.MVVM;
using Catel.MVVM.Services;
using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using DevExpress.Xpo.DB.Exceptions;
using LprMiddleWare.DAL;
using LprMiddleWare.HangWang;
using System.Reactive.Linq;
using System.Linq;
using System;
using LprMiddleWare.Converters;
using MiscUtil;
using NLog;
using TlvLib;
using TlvLib.Packets;
using TlvLib.SiChuan;
using ErrorEventArgs = LprMiddleWare.HangWang.ErrorEventArgs;
using TimeConverter = LprMiddleWare.DAL.TimeConverter;

namespace LprMiddleWare.ViewModels
{
    using Model;

    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();
        private Settings _settings = Settings.LoadDefault();

        private ObservableCollection<LogEntry> _logs;
        private ConcurrentBag<System.Net.IPAddress> _hosts = new ConcurrentBag<IPAddress>();
        private List<TlvLib.PacketHandler> _packetHandlers;
        private readonly ConcurrentBag<LicensePlate> _licensePlateInfos
            = new ConcurrentBag<LicensePlate>();

        private ColorMap[] _colorMaps;

        private ConcurrentDictionary<string, CameraStatus> _cameraStatuses
            = new ConcurrentDictionary<string, CameraStatus>();

        private ConcurrentQueue<TogVehmon> _remoteSyncQueue
            = new ConcurrentQueue<TogVehmon>();

        private ConcurrentQueue<CameraStatus> _cameraStatusQueue
            = new ConcurrentQueue<CameraStatus>();

        private IMessageService _messageService;
        private UploadService _uploadService;

        private string _sqlCommandPattern =
            "select v.txwz, v.txmc1, v.txmc2, v.txmc3, v.txmc4, v.spwz, v.spmc, v.spmc1, v.spmc2  from tog_vehmon v where jgsk<sysdate-{0} AND not exists (select * from tog_vehblack b where v.hphm=b.hphm) AND not exists (select * from tog_vehdispalarm a where v.hphm=a.hphm AND a.jgsk>sysdate-{1})  AND not exists (select * from tog_vehmon m where v.mvid=m.mvid AND m.wzbj='1' AND m.jgsk>sysdate-{2})";

        private string _sqlDeleteCommandPattern =
            "delete tog_vehmon v where jgsk<sysdate-{0} AND not exists (select * from tog_vehblack b where v.hphm=b.hphm) AND not exists (select * from tog_vehdispalarm a where v.hphm=a.hphm AND a.jgsk>sysdate-{1})  AND not exists (select * from tog_vehmon m where v.mvid=m.mvid AND m.wzbj='1' AND m.jgsk>sysdate-{2})";

        private bool _enableRefreshing;
        public bool EnableRefreshingLog
        {
            get { return _enableRefreshing; }
            set
            {
                _enableRefreshing = value;
                RaisePropertyChanged("EnableRefreshing");
            }
        }

        private LicensePlate _currentPlate;
        public LicensePlate CurrentPlate
        {
            get { return _currentPlate; }
            set
            {
                _currentPlate = value;
                RaisePropertyChanged("CurrentPlate");
            }
        }

        public Settings Settings { get; set; }
        public Command ClearLogCommand { get; private set; }

        private Visibility _lprVisibility;
        public Visibility LprVisibility
        {
            get { return _lprVisibility; }
            set
            {
                _lprVisibility = value;
                RaisePropertyChanged("LprVisibility");
            }
        }

        public ObservableCollection<LogEntry> Logs
        {
            get { return _logs ?? (_logs = new ObservableCollection<LogEntry>()); }
        }


        // private BitmapImage _currentImage;
        private Thread _syncWorker;
        private Thread _dbWorker;
        private Thread _deleteWorker;
        private bool _isDeleteInProgress;

        /// <summary>
        /// Gets or sets the property value.
        /// </summary>
        public BitmapImage CurrentImage
        {
            get { return GetValue<BitmapImage>(CurrentImageProperty); }
            set { SetValue(CurrentImageProperty, value); }
        }

        /// <summary>
        /// Register the CurrentImage property so it is known in the class.
        /// </summary>
        public static readonly PropertyData CurrentImageProperty = RegisterProperty("CurrentImage", typeof(BitmapImage), null);

        //public BitmapImage CurrentImage
        //{
        //    get { return _currentImage; }
        //    set
        //    {
        //        _currentImage = value;
        //        RaisePropertyChanged("CurrentImage");
        //    }
        //}


        public ICommand SaveSettingsCommand { get; set; }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
            _lprVisibility = Visibility.Collapsed;

            ClearLogCommand = new Command(ClearLog);
            EnableRefreshingLog = true;

            if (false)
            {
                LogMessage("test log");
                CurrentImage = new BitmapImage(new Uri(@"/Images/TestPlate.jpg", UriKind.Relative));

                CurrentPlate = new LicensePlate();
                CurrentPlate.LicenseNumber = "川ABCD1234";
                CurrentPlate.DeviceId = "十字路口";
                CurrentPlate.LaneNo = 1;
                CurrentPlate.CaptureTime = DateTime.Now;
            }
            else
            {
                _messageService = GetService<IMessageService>();
                Settings = Settings.LoadDefault();

                if (_settings.UploadWeiZhangData)
                {
                    _uploadService = new UploadService(this.LogMessage);
                }

                if (_settings.Save2Db)
                {
                    _dbWorker = new Thread(() => SyncFunc(false, dl =>
                                                                     {
                                                                         var s1 = SaveLprs(dl);
                                                                         var s2 = AddCameraStatusToDatabase(dl);

                                                                         if (!s2 && !s1)
                                                                         {
                                                                             //LogMessage("没有数据需要同步到本地数据库，睡眠10秒");
                                                                             Thread.Sleep(50);
                                                                         }

                                                                     }));
                    _dbWorker.IsBackground = true;
                    _dbWorker.Start();
                }

                if (_settings.Save2RemoteDb)
                {
                    _syncWorker = new Thread(SyncToRemoteDbThread);
                    _syncWorker.IsBackground = true;
                    _syncWorker.Start();
                }

                if (_settings.AutoDelOutdateData)
                {
                    if (!string.IsNullOrEmpty(_settings.DbServer)
                    && !string.IsNullOrEmpty(_settings.DbUserName)
                    && !string.IsNullOrEmpty(_settings.DbPassWord))
                    {
                        var ob = Observable.Interval(TimeSpan.FromMinutes(30));  //每隔30分钟检查一次
                        ob.Subscribe(DelOutDatedData);
                    }
                    else
                    {
                        _messageService.ShowError("数据库配置有错误，自动删除过期数据无法运行");
                    }
                }

                InitColorMapper();
                InitUnpacker();
                // InitSichuan();
            }
        }

        private void InitSichuan()
        {
            _facade = new Facade(new IPEndPoint(IPAddress.Parse("192.168.1.10"), 8886));
            _facade.ConnectionEstablished += FacadeOnConnectionEstablished;
            _facade.ConnectionClosed += FacadeOnConnectionClosed;
            _facade.ErrorOccurred += FacadeOnErrorOccurred;
            _facade.FirstRegisterSucceed += FacadeOnRegisterSucceed;
            _facade.SecondRegisterSucceed += FacadeOnSecondRegisterSucceed;
            _facade.Start();
        }

        private void FacadeOnSecondRegisterSucceed(object sender, EventArgs eventArgs)
        {
            LogMessage("二次注册成功");
        }

        private void FacadeOnConnectionClosed(object sender, EventArgs eventArgs)
        {
            LogMessage("数据提交链路断开");
        }

        private void FacadeOnRegisterSucceed(object sender, EventArgs eventArgs)
        {
            LogMessage("一次注册成功");
        }

        private void FacadeOnErrorOccurred(object sender, EventArgs<Exception> eventArgs)
        {
            LogMessage("连接省机动车提交平台发生异常: " + eventArgs.Value.Message);
        }

        private void FacadeOnConnectionEstablished(object sender, EventArgs eventArgs)
        {
            LogMessage("数据提交链路建立成功");
        }

        protected override void OnUninitializing()
        {
            base.OnUninitializing();

            _logger.Info("开始退出程序");
            ShutdownHandlers();

        }

        private void DelOutDatedData(long l)
        {
            if (_isDeleteInProgress) return;
            DateTime now = DateTime.Now;
            //if (now.Hour < 1 || now.Hour > 4) return; //只在夜间做删除

            _isDeleteInProgress = true;
            try
            {
                var msg = "开始删除过期数据";
                _logger.Info(msg);
                LogMessage(msg);
                using (var dl = Helper.ConnectToOracleDb(_settings.DbServer, _settings.DbUserName, _settings.DbPassWord))
                {
                    DeleteOutdateVideoOrImage(dl, string.Format(_sqlCommandPattern, _settings.VideoKeepDays, _settings.BuKongVideoKeepDays, _settings.WeiFaVideoKeepDays), DelVideos);
                    DeleteOutdateVideoOrImage(dl, string.Format(_sqlCommandPattern, _settings.ImageKeepDays, _settings.BuKongImageKeepDays, _settings.WeiFaImageKeepDays), DelImages);
                    DeleteOutdateData(dl);
                }

                msg = "删除过期数据完毕";
                _logger.Info(msg);
                LogMessage(msg);
            }
            catch (Exception ex)
            {
                _logger.ErrorException("删除过期数据时发生异常", ex);
                LogMessage("删除过期数据时发生异常" + ex.Message);
            }
            finally
            {
                _isDeleteInProgress = false;
            }
        }

        private void DelImages(Record[] obj)
        {
            DelFiles(obj, true);
        }

        private void DelVideos(Record[] obj)
        {
            DelFiles(obj, false);
        }

        private void DelFiles(Record[] records, bool deleteImage)
        {
            _fileErrorCount = 0;
            _fileSuccessCount = 0;
            foreach (var record in records)
            {
                if (deleteImage)
                {
                    DelRecordFiles(record.TXWZ, record.TXMC);
                }
                else
                {
                    DelRecordFiles(record.SPWZ, record.SPMC);
                }

            }

            var msg = string.Format("删除 {0} 个{1}文件", _fileSuccessCount, deleteImage ? "图片" : "视频");
            _logger.Info(msg);
        }

        int _fileErrorCount = 0;
        private int _fileSuccessCount = 0;
        private Facade _facade;

        private void DelRecordFiles(string directory, string[] fileNames)
        {

            if (!string.IsNullOrEmpty(directory))
            {
                foreach (var name in fileNames)
                {
                    if (!string.IsNullOrEmpty(name))
                    {
                        var path = Path.Combine(directory, name);
                        if (File.Exists(path))
                        {
                            try
                            {
                                File.Delete(path);
                                _fileSuccessCount++;
                            }
                            catch (Exception ex)
                            {
                                if (_fileErrorCount <= 10)
                                {
                                    _logger.ErrorException("删除文件发生错误(最多记录10条文件操作错误)", ex);
                                }
                                ++_fileErrorCount;

                            }
                        }
                        else
                        {
                            if (_fileErrorCount <= 10)
                            {
                                _logger.Info("文件 " + path + "不存在(最多记录10条文件操作错误)");
                            }
                            ++_fileErrorCount;

                        }
                    }
                }
            }
        }

        private void DeleteOutdateData(IDataLayer dataLayer)
        {
            using (var uow = new UnitOfWork(dataLayer))
            {
                var sqlCommand = string.Format(_sqlDeleteCommandPattern, _settings.DataKeepDays, _settings.BuKongDataKeepDays,
                                               _settings.WeiFaDataKeepDays);
                var count = uow.ExecuteNonQuery(sqlCommand);
                _logger.Info("删除 {0} 条记录", count);
            }
        }

        private void DeleteOutdateImages(IDataLayer dataLayer)
        {
            throw new NotImplementedException();
        }

        private void DeleteOutdateVideoOrImage(IDataLayer dataLayer, string sqlCommand, Action<Record[]> action)
        {
            using (var uow = new UnitOfWork(dataLayer))
            {
                var result = uow.ExecuteQuery(sqlCommand);
                if (ResultSetHasValidData(result))
                {
                    var records = ConvertResultToRecords(result);
                    action(records);
                }
            }
        }

        private Record[] ConvertResultToRecords(SelectedData result)
        {
            if (ResultSetHasValidData(result))
            {
                var results = new List<Record>();
                foreach (var row in result.ResultSet[0].Rows)
                {
                    var r = new Record();
                    r.TXWZ = Convert.ToString(row.Values[0]);
                    r.TXMC = new string[4];
                    r.TXMC[0] = Convert.ToString(row.Values[1]);
                    r.TXMC[1] = Convert.ToString(row.Values[2]);
                    r.TXMC[2] = Convert.ToString(row.Values[3]);
                    r.TXMC[3] = Convert.ToString(row.Values[4]);
                    r.SPWZ = Convert.ToString(row.Values[5]);
                    r.SPMC = new string[3];
                    r.SPMC[0] = Convert.ToString(row.Values[6]);
                    r.SPMC[1] = Convert.ToString(row.Values[7]);
                    r.SPMC[2] = Convert.ToString(row.Values[8]);
                    results.Add(r);
                }
                return results.ToArray();
            }

            return new Record[0];
        }

        private bool ResultSetHasValidData(SelectedData resultSet)
        {
            if (resultSet.ResultSet.Length > 0 && resultSet.ResultSet[0].Rows.Length > 0)
            {
                if (resultSet.ResultSet[0].Rows[0].Values.Length < 9)
                {
                    _logger.Error("数据库配置错误，查询过期数据时返回的字段数目不足");
                    return false;
                }

                return true;
            }

            return false;
        }

        private void SyncFunc(bool remote, Action<IDataLayer> action)
        {
            var dbname = remote ? "远程数据库" : "本地数据库";
            while (true)
            {
                using (var dl = Helper.ConnectToDbUntilSuccess(
                    remote ? _settings.RemoteDbServer : _settings.DbServer,
                    remote ? _settings.RemoteDbUserName : _settings.DbUserName,
                    remote ? _settings.RemoteDbUserName : _settings.DbPassWord))
                {
                    while (true)
                    {
                        try
                        {
                            action(dl);
                        }
                        catch (Exception ex)
                        {
                            _logger.ErrorException("同步数据到" + dbname + "发生异常", ex);
                            LogMessage("同步数据到" + dbname + "发生异常:" + ex.Message);

                            if (IsDbDisConnectedException(ex))
                            {
                                LogMessage("数据库连接中断");
                                break;
                            }
                        }

                    }
                }



            }
        }

        private bool IsDbDisConnectedException(Exception exception)
        {
            return exception is System.Data.OracleClient.OracleException;

            var ex = exception.InnerException as System.Data.OracleClient.OracleException;
            return ex.Code == 3113;
        }

        private void SyncToRemoteDbThread()
        {
            try
            {
                while (true)
                {
                    using (var remoteDbLayer = Helper.ConnectToDbUntilSuccess(_settings.RemoteDbServer, _settings.RemoteDbUserName, _settings.RemoteDbPassWord))
                    using (var localDbLayer = Helper.ConnectToDbUntilSuccess(_settings.DbServer, _settings.DbUserName, _settings.DbPassWord))
                    {
                        while (true)
                        {
                            try
                            {
                                //LogMessage("远程数据库连接成功， 开始同步数据到远程数据库");
                                var res = SyncHistoryData(localDbLayer, remoteDbLayer);
                                if (!res)
                                {
                                    //LogMessage("没有数据需要同步，睡眠10秒");
                                    Thread.Sleep(50);
                                }
                            }
                            catch (System.Data.OracleClient.OracleException ex)
                            {
                                _logger.ErrorException("保存到远程数据库发生异常。", ex);
                                LogMessage("保存到远程数据库发生异常：" + ex.Message);

                                break;
                            }

                        }


                    }
                }
            }
            catch (Exception ex)
            {
                _logger.ErrorException("远程同步线程发生异常退出", ex);
                
            }
            
        }




        private bool SyncHistoryData(IDataLayer localDbLayer, IDataLayer remoteDbLayer)
        {
            using (var session = new Session(localDbLayer))
            {
                var page = new XPCursor(session, typeof(CarInfo_Qx));
                page.PageSize = 100;
                page.TopReturnedObjects = 100;
                


                if (page.Count > 0)
                {
                    using (var uow = new UnitOfWork(remoteDbLayer))
                    {
                        foreach (CarInfo_Qx info in page)
                        {
                            var infoRemote = new CarInfo_Qx(uow);
                            infoRemote.CLTGSJ = info.CLTGSJ;
                            infoRemote.HPHM = info.HPHM;
                            infoRemote.HPZL = info.HPZL;
                            infoRemote.KKJLID = info.KKJLID;
                            infoRemote.KKMC = info.KKMC;
                            infoRemote.KKMCDM = info.KKMCDM;
                            infoRemote.SSDWDM = info.SSDWDM;
                            infoRemote.SSDWMC = info.SSDWMC;
                            infoRemote.XSCD = info.XSCD;
                            infoRemote.XSFXDM = info.XSFXDM;
                        }

                        uow.CommitChanges();

                        foreach (CarInfo_Qx info in page)
                        {
                            info.Delete();
                        }
                        session.PurgeDeletedObjects();


                        var msg = string.Format("同步{0}条历史数据到远程数据库成功", page.Count);
                        LogMessage(msg);

                    }

                    return true;
                }

                return false;

            }

        }


        private bool CommitUow(UnitOfWork uow)
        {
            try
            {
                uow.CommitChanges();
            }
            catch (Exception ex)
            {
                _logger.ErrorException("保存到远程数据库发生异常。", ex);
                LogMessage("保存到远程数据库发生异常：" + ex.Message);
                return false;
            }

            return true;
        }

        private void StartOrPauseRefresh()
        {
            throw new NotImplementedException();
        }

        void Default_SettingChanging(object sender, System.Configuration.SettingChangingEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void InitColorMapper()
        {
            var reader = new FileHelpers.DelimitedFileEngine<ColorMap>();
            _colorMaps = reader.ReadFile("Kise-Color.txt");
        }

        private void InitUnpacker()
        {
            _packetHandlers = new List<PacketHandler>();

            foreach (var ipPort in Settings.Hosts.Where(i => i.Enabled))
            {
                var h = new PacketHandler(ipPort.IpAddress, ipPort.Port);
                h.NewPacketReceived += _packetHandler_NewPacketReceived;
                h.ReportStatus += h_ReportStatus;
                h.SetLogger(LogMessage);
                _packetHandlers.Add(h);
                h.Start();
            }

        }

        private void ShutdownHandlers()
        {
            foreach (var h in _packetHandlers)
            {
                h.Stop();
            }
        }


        private void ClearLog()
        {
            _logs.Clear();
        }

        void h_ReportStatus(object sender, MiscUtil.EventArgs<string> args)
        {
            LogMessage(args.Value);
        }

        private bool SaveLprs(IDataLayer dataLayer)
        {
            var result = false;
            if (!_licensePlateInfos.IsEmpty)
            {
                using (var uow = new UnitOfWork(dataLayer))
                {
                    var count = 0;
                    while (!_licensePlateInfos.IsEmpty && count < 100)
                    {
                        var lpr = default(LicensePlate);
                        _licensePlateInfos.TryTake(out lpr);
                        var record = SaveCaptureRecord(lpr, uow);
                        ++count;
                    }
                    try
                    {
                        uow.CommitChanges();
                        result = true;
                        var msg = string.Format("保存{0}条记录到本地数据库成功", count);
                        LogMessage(msg);
                    }
                    catch (Exception ex)
                    {
                        _logger.ErrorException("保存记录到数据库发生异常", ex);
                        LogMessage("无法保存记录到数据库，该异常已经被记录到log中");
                        throw;
                    }

                    System.Diagnostics.Debug.WriteLine("commit changes");
                }
            }

            return result;
        }

        private void UploadToSichuanPlatform(LicensePlate record)
        {
            var data = ConvertToCarInfo(record);
            _facade.SendData(data);
        }

        private CarInfo ConvertToCarInfo(LicensePlate record)
        {
            var res = new CarInfo();
            res.CDBH = record.LaneNo.ToString("d2");
            res.CTHPHM = string.IsNullOrEmpty(record.LicenseNumber) ? "noplate" : record.LicenseNumber;
            res.FXBH = Configuration.FXBH;
            res.HPYZ = "3";
            res.JGSJ = record.CaptureTime;
            res.KKBH = Configuration.KKBH;
            res.SBBH = Configuration.SBBH;
            res.CLSD = record.Speed;
            res.CTHPYS = (ushort)record.PlateType;

            var urls = ConvertToUrls(record.Images);

            res.TXLJs = urls;

            return res;
        }


        //http://192.168.1.155:8080/vehimg/2012/05/25/11/1001/1-11394558400.jpg
        private string[] ConvertToUrls(List<string> images)
        {
            var result = new string[images.Count];
            for (int i = 0; i < images.Count; i++)
            {
                var url = "http://192.168.1.155:8080/vehimg" + images[i].Replace("\\", "/").Replace("d:/vehimg", "");
                result[i] = url;
            }

            return result;
        }


        private CarInfo_Qx SaveToSyncDb(TogVehmon savedRecord, Lane lane, Session session)
        {
            var carinfo = new CarInfo_Qx(session);
            carinfo.CLTGSJ = savedRecord.JGSK;
            carinfo.KKJLID = savedRecord.MVID;
            carinfo.KKMCDM = lane.KKMCDM;
            carinfo.KKMC = lane.KakouName;
            carinfo.HPZL = savedRecord.HPZL;
            carinfo.HPHM = savedRecord.HPHM;
            carinfo.XSFXDM = Convert.ToChar(savedRecord.FXBH.Last());
            carinfo.XSCD = savedRecord.CDBH.Last().ToString();
            carinfo.SSDWDM = lane.SSDWDM;
            carinfo.SSDWMC = lane.SSDWMC;
            return carinfo;
        }

        void _packetHandler_NewPacketReceived(object sender, NewPacketEventArgs args)
        {
            if (args.Packet is LicensePlateInfo)
            {
                HandleLicensePlateInfo(args.Packet as LicensePlateInfo);
            }
            else if (args.Packet is CameraStatus)
            {
                HandleCameraStatus(args.Packet as CameraStatus);
            }
        }

        private void HandleCameraStatus(CameraStatus cameraStatus)
        {
            if (string.IsNullOrEmpty(cameraStatus.StationId))
            {
                LogMessage("设备状态数据非法，StationId为空，丢弃该数据包");
                return;
            }

            var writeDb = false;
            var key = GetKey(cameraStatus);
            if (_cameraStatuses.ContainsKey(key))
            {
                var old = _cameraStatuses[key];
                if (old.StateCode != cameraStatus.StateCode) //与上次的状态不同，写数据库
                {
                    writeDb = true;
                }
            }
            else//新状态，写数据库
            {
                writeDb = true;
            }

            if (_settings.Save2Db && writeDb)
            {
                if (_cameraStatusQueue.Count < 10)
                {
                    _cameraStatusQueue.Enqueue(cameraStatus);
                }
                else
                {
                    LogMessage("设备状态队列已满，请检查数据库连接是否正常");
                }
                _cameraStatuses.AddOrUpdate(key, cameraStatus, (k, old) => cameraStatus);
            }

        }

        private static string GetKey(CameraStatus cameraStatus)
        {
            var key = cameraStatus.StationId + cameraStatus.DirectionNo + cameraStatus.CameraId;
            return key;
        }

        private bool AddCameraStatusToDatabase(IDataLayer dataLayer)
        {
            var result = false;
            try
            {
                if (_cameraStatusQueue.Count > 0)
                {
                    using (var uow = new UnitOfWork(dataLayer))
                    {
                        CameraStatus cs;
                        if (_cameraStatusQueue.TryDequeue(out cs))
                        {
                            var toggate = Repository.Instance.GetTollGate(uow, cs.StationId);
                            if (toggate == null)
                            {
                                var msg = string.Format("卡口查询出错（卡口编号 = {0}）, 无法保存设备状态到数据库。 ", cs.StationId);
                                LogMessage(msg);
                                return result;
                            }

                            var status = new TOG_DEVBUG(uow);
                            status.DBID = Guid.NewGuid().ToString();
                            status.WLZT = DeviceIsAbnormal(cs) ? "1" : "0"; //0:正常，1：故障
                            status.SBBH = cs.StationId;
                            status.SBMC = toggate.KKMC;
                            status.BJSJ = DateTime.Now;
                            status.CLZT = DeviceIsAbnormal(cs) ? '0' : '1'; //设备状态正常时，处理标志置为已处理
                            status.BZ = "相机" + cs.Ip + (cs.StateCode == 0 ? "连接中断" : "连接正常");
                            //status.Save(); 
                        }

                        uow.CommitChanges();
                        result = true;
                    }
                }

                return result;

            }
            catch (Exception ex)
            {
                LogMessage("添加设备状态到数据库是发生异常: " + ex);
                throw;
            }
        }

        private static bool DeviceIsAbnormal(CameraStatus cameraStatus)
        {
            return cameraStatus.StateCode == 0;
        }


        private void HandleLicensePlateInfo(LicensePlateInfo lpi)
        {
            if (lpi.Images.Length > 0)
            {
                IList<string> imagePaths = null;
                try
                {
                    imagePaths = SaveImages(lpi);
                }
                catch (IOException ex)
                {
                    LogMessage("文件存储出错，无法保存图片，" + ex.Message);
                    return;
                }
                catch (DevExpress.Xpo.DB.Exceptions.SqlExecutionErrorException)
                {
                    var msg = string.Format("数据库查询出错，无法保存图片, DeviceId={0}, Direction={1}, Lane={2} ",
                                            lpi.MonitorId, lpi.Direction, lpi.RoadNo);
                    LogMessage(msg);
                    return;
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("保存图片时发生异常", ex);
                    var msg = "保存图片发生异常，该异常已经被记录到log中。";
                    LogMessage(msg);
                    return;
                }

                if (imagePaths.Count == 0)
                {
                    return;
                }
                var lpr = new LicensePlate()
                              {
                                  LicenseNumber = lpi.PlateNo,
                                  PlateColor = lpi.PlateColor,
                                  CarType = lpi.CarType,
                                  CaptureTime = lpi.Images[0].CaptureTime,
                                  Images = new List<string>(imagePaths),
                                  DeviceId = lpi.MonitorId,
                                  LaneNo = lpi.RoadNo,
                                  Speed = lpi.Speed,
                                  SpeedLimit = lpi.SpeedLimit,
                                  CameraNo = lpi.CameraNo,
                                  Confidence = lpi.Confidence,
                                  DetectMethod = lpi.DetectMethod,
                                  Direction = lpi.Direction
                              };

                lpi.Images = null;

                if (_settings.UploadWeiZhangData)
                {
                    _uploadService.Upload(lpr);
                }

                if (_settings.Save2Db)
                {
                    if (_licensePlateInfos.Count < 1000)
                    {
                        _licensePlateInfos.Add(lpr);
                    }
                    else
                    {
                        LogMessage("数据库存储队列已满，请检查数据库连接是否正常！");
                    }

                }

                // UploadToSichuanPlatform(lpr);


                Action<LicensePlate> ac = OnNewLpr;
                Application.Current.Dispatcher.BeginInvoke(ac, lpr);
            }
        }


        private void OnError(ErrorEventArgs eventArgs)
        {
            LogMessage("发生错误：" + eventArgs.Message);
        }

        private void LogMessage(string message)
        {
            Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                                                                      {
                                                                          if (EnableRefreshingLog)
                                                                          {
                                                                              //only keep 50 logs
                                                                              if (Logs.Count > 50)
                                                                              {
                                                                                  Logs.RemoveAt(Logs.Count - 1);
                                                                              }

                                                                              var log = new LogEntry() { Message = message };
                                                                              Logs.Insert(0, log);

                                                                          }

                                                                      }));
        }

        private void OnNewLpr(LicensePlate lpr)
        {
            if (!Application.Current.MainWindow.IsVisible) return;

            CurrentPlate = lpr;

            if (lpr.Images.Count <= 0)
            {
                LogMessage("警告，车牌图片数目为 " + lpr.Images.Count);
            }



            if (lpr.Images.Count > 0 && File.Exists(lpr.Images[0]))
            {
                BitmapImage img = null;
                img = LoadImage(lpr);

                CurrentImage = img;
            }
        }

        private BitmapImage LoadImage(LicensePlate lpr)
        {
            BitmapImage img = null;
            try
            {
                img = new BitmapImage();
                img.BeginInit();
                img.UriSource = new Uri(lpr.Images[0]);
                img.CacheOption = BitmapCacheOption.None;
                img.CreateOptions = BitmapCreateOptions.DelayCreation;
                img.EndInit();
            }
            catch (Exception ex)
            {
                LogMessage("显示图片时发生错误：" + ex.Message);
            }
            return img;
        }

        private TogVehmon SaveCaptureRecord(LicensePlate licensePlate, UnitOfWork uow)
        {
            Lane lane;
            var laneDetail = GetLocation(uow, licensePlate, out lane);
            if (lane == null || laneDetail == null)
            {
                var msg = FormatMessage(licensePlate.DeviceId, licensePlate.Direction, licensePlate.LaneNo);
                LogMessage(msg);
                LogMessage("无法保存记录到数据库！");
                return null;
            }

            if (lane.KKMCDM.Length < 12)
            {
                LogMessage("数据库配置错误，卡口名称代码小于12位");
                return null;
            }

            //是否超速
            if (licensePlate.CaptureReason == CaptureReason.Normal)
            {
                if (laneDetail.XDSD != 0)
                {
                    if (licensePlate.Speed > laneDetail.XDSD)
                    {
                        licensePlate.CaptureReason = CaptureReason.OverSpeed;
                    }
                }
            }

            var record = new TogVehmon(uow);

            //地点信息
            record.KKBH = lane.KaKouNo;
            record.KKMC = lane.KakouName;
            record.FXBH = lane.DirectionNo;
            record.FXMC = lane.DirectionName;
            record.CDBH = lane.LaneNo;
            record.CDMC = lane.LaneName;
            var sn = GetSequenceNumber(uow);
            record.MVID = string.Format("{0}{1:D12}", lane.KKMCDM.Substring(0, 12), sn);
            record.CLXXBH = sn.ToString(CultureInfo.InvariantCulture);
            //事件
            record.WZYY = PunishReasonConverter.Convert(licensePlate.CaptureReason);
            record.CLSD = licensePlate.Speed;
            record.XS = laneDetail.XDSD;
            record.SFCS = licensePlate.CaptureReason == CaptureReason.OverSpeed ? "1" : "0";
            if (licensePlate.CaptureReason != CaptureReason.Normal)
            {
                record.WZBJ = '1';
                if (laneDetail.XDSD > 0 && licensePlate.CaptureReason == CaptureReason.OverSpeed)
                {
                    record.CSB = ((decimal)licensePlate.Speed - laneDetail.XDSD) / laneDetail.XDSD;
                }
            }
            else
            {
                record.WZBJ = '0';
            }
            //时间
            record.JGSK = licensePlate.CaptureTime;
            record.TJRQ = TimeConverter.ToTongJiRiQi(licensePlate.CaptureTime);
            //车牌信息
            record.HPHM = string.IsNullOrEmpty(licensePlate.LicenseNumber) ? "00000" : licensePlate.LicenseNumber;
            record.SBZT = string.IsNullOrEmpty(licensePlate.LicenseNumber) ? "1" : "0";
            var id = PlateTypeConverter.Convert(licensePlate.PlateType);
            var lpr = Repository.Instance.GetLprType(uow, id);
            record.HPZL = lpr.HPZLDM;
            record.HPZLMC = lpr.HPMC;
            var color = FindColorInDb(licensePlate.PlateColor);
            record.HPYS = color.DbColorString;
            record.HPYSBH = color.DbColorCode.ToString();
            //图片
            if (licensePlate.Images.Count >= 1)
            {
                record.TXMC1 = Path.GetFileName(licensePlate.Images[0]);
                var dir = Path.GetDirectoryName(licensePlate.Images[0]);
                var dirPath = new NDepend.Helpers.FileDirectoryPath.DirectoryPathAbsolute(dir);
                var root = new NDepend.Helpers.FileDirectoryPath.DirectoryPathAbsolute(_settings.TargetDirectory);
                record.TXWZ = dir.Replace("\\", "/") + "/";
                record.TXURL = "/vehimg" + dirPath.GetPathRelativeFrom(root).Path.Remove(0, 1).Replace("\\", "/") + "/";

            }
            if (licensePlate.Images.Count >= 2)
            {
                record.TXMC2 = Path.GetFileName(licensePlate.Images[1]);
            }
            if (licensePlate.Images.Count >= 3)
            {
                record.TXMC3 = Path.GetFileName(licensePlate.Images[2]);
            }

            if (_settings.Save2RemoteDb)
            {
                SaveToSyncDb(record, lane, uow);
            }

            return record;
        }


        private int GetSequenceNumber(Session session)
        {
            var obj = session.ExecuteScalar("SELECT CLXXBH_SEQ.NEXTVAL FROM DUAL");
            return Convert.ToInt32(obj);
        }

        private ColorMap FindColorInDb(int colorCode)
        {
            return _colorMaps.FirstOrDefault(colorMap => colorMap.KiseColorCode == colorCode);
        }

        private static TogTollgate GetLocation(Session session, LicensePlate licensePlate, out Lane lane)
        {
            lane = Repository.Instance.GetLane(session, licensePlate.DeviceId, licensePlate.Direction, licensePlate.LaneNo.ToString("d2"));
            if (lane == null)
            {
                return null;
            }

            var laneDetail = Repository.Instance.GetTollGate(session, lane.LaneNo);
            return laneDetail;
        }


        //打字格式
        //日期： 时间： 地点：
        //设备编号：  方向：
        private IList<string> SaveImages(LicensePlateInfo licensePlate)
        {
            var result = new List<string>(); int count = 0;

            foreach (var bitmapData in licensePlate.Images)
            {
                //var img = Image.FromStream(new MemoryStream(bitmapData));
                //var overlayImageId = DrawOverlayText(licensePlate, captureAt, img);
                var relative = GetRelativeImagePathNew(bitmapData.CaptureTime, licensePlate.MonitorId, licensePlate.RoadNo.ToString(), count++);
                System.Diagnostics.Debug.WriteLine(relative);
                var path = Path.Combine(_settings.TargetDirectory, relative);

                var dir = Path.GetDirectoryName(path);
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                File.WriteAllBytes(path, bitmapData.ImageBuffer);
                //_gdPictureImaging.SaveAsJPEG(overlayImageId, path);
                //_gdPictureImaging.ReleaseGdPictureImage(overlayImageId);
                //img.Dispose();
                result.Add(path);
            }

            return result;
        }

        private static string FormatMessage(string deviceId, string dirId, int laneId)
        {
            var message = string.Format("无法查询到车道信息, DeviceId = {0}, DirNo = {1}, LaneNo = {2}", deviceId, dirId, laneId);
            return message;
        }


        private void OnDeviceStatus(EventPattern<DeviceStatusEventArgs> arg)
        {
            //if (arg.EventArgs.Status == DeviceStatus.Connected)
            //{
            //    if (!_hosts.Contains(arg.EventArgs.Ip))
            //    {
            //        _hosts.Add(arg.EventArgs.Ip);
            //    }
            //}
            //else if (arg.EventArgs.Status == DeviceStatus.DisConnected)
            //{
            //    IPAddress ip;
            //    _hosts.TryTake(out ip);
            //}

            var msg = string.Format("{0}:{1} 来自设备 {2}", (arg.EventArgs.Status == DeviceStatus.Connected ? "连接" : "断开"), arg.EventArgs.Ip, arg.EventArgs.DeviceId);
            var item = new LogEntry()
                           {
                               Message = msg
                           };
            LogMessage(msg);
        }

        private string GetRelativeImagePath(DateTime captureTime, Lane captureFrom, int index)
        {
            return string.Format("{0:d4}/{1:d2}/{2:d2}/{3}-{4:d4}{5:d2}{6:d2}{7:d2}{8:d2}{9:d2}-{10}.jpg",
                                 captureTime.Year, captureTime.Month, captureTime.Day,
                                 captureFrom.LaneNo,
                                 captureTime.Year, captureTime.Month, captureTime.Day, captureTime.Hour,
                                 captureTime.Minute, captureTime.Second,
                                 index);
        }


        //按新标准命名
        private string GetRelativeImagePathNew(DateTime captureTime, string kakouNo, string laneNo, int index)
        {
            return string.Format("{0:d4}/{1:d2}/{2:d2}/{3:d2}/{4}/{5}-{6:d2}{7:d2}{8:d2}{9:d3}{10:d2}.jpg",
                                 captureTime.Year, captureTime.Month, captureTime.Day, captureTime.Hour, kakouNo,
                                 laneNo, captureTime.Hour, captureTime.Minute, captureTime.Second, captureTime.Millisecond, index);
        }
    }

    class Record
    {
        public string TXWZ;
        public string[] TXMC;

        public string SPWZ;
        public string[] SPMC;

    }
}